//
//  ServerEngine.m
//  MobileOA
//
//  Created by chenxiaojuan on 13-4-16.
//  Copyright (c) 2013年 chenxiaojuan. All rights reserved.
//

#import "ServerEngine.h"
#import "JSONKit.h"
#import "AFHTTPClient.h"
#import "AFHTTPRequestOperation.h"
#import "StorageEngine.h"
#import "NSData+Base64.h"
#import <CommonCrypto/CommonCryptor.h>
#import "Class+Plugins.h"

static unsigned char base64EncodeLookup[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//#define xx 65
//static unsigned char base64DecodeLookup[256] =
//{
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, 62, xx, xx, xx, 63,
//    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, xx, xx, xx, xx, xx, xx,
//    xx,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
//    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, xx, xx, xx, xx, xx,
//    xx, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
//    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//    xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx,
//};

@interface ServerEngine (){
    NSString* _serverName;
    NSString* _serverProjectName;
    NSString* _serverPort;
    NSString* _serverUri;
}

@end

@implementation ServerEngine

-(NSString*)encodeCmd:(NSString*)cmd params:(NSDictionary*)params
{
    NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
    NSMutableDictionary* head = [[[NSMutableDictionary alloc] init] autorelease];
    NSDictionary* data = params;
    [dict setObject:head forKey:@"head"];
    [dict setObject:data forKey:@"data"];
    
    [head setObject:cmd forKey:@"command_id"];
    [head setObject:@"" forKey:@"request_tick"];
    [head setObject:DE.terminalId forKey:@"terminal_id"];
    [head setObject:DE.terminalName forKey:@"terminal_name"];
    [head setObject:DE.appId forKey:@"app_id"];
    [head setObject:DE.userId forKey:@"user_id"];
    [head setObject:DE.userPassword forKey:@"user_password"];
    [head setObject:DE.osName forKey:@"osName"];
    [head setObject:DE.osVersion forKey:@"osVersion"];
    
    NSString * json =[dict JSONString];

    NSString* str = [ServerEngine encryptDES: json key:@"12345678"];
    return str;
}

+(NSDictionary*)decodeCmd:(NSString*)cmd_string
{
    cmd_string = [ServerEngine decryptDES:cmd_string key:@"12345678"];
    return [cmd_string objectFromJSONString];
}

+(NSString*)getMD5FromRequest:(NSString*)name params:(NSDictionary*)params
{
    NSString* md5 =[NSString stringWithFormat:@"%@:%@",name,[params JSONString]];
    return [md5 md5Hash];
}

+(NSDictionary*)readDataFromCache:(NSString*)name params:(NSDictionary*)params
{
    NSString* filename = [ServerEngine getMD5FromRequest:name params:params];
    filename = [NSString stringWithFormat:@"%@%@",DE.cachePath,filename];
    NSString* response_string = [StorageEngine readFile:filename];
    if ( response_string == nil )
        return nil;
    NSDictionary* response = [ServerEngine decodeCmd:response_string];
    if ( response == nil )
        return nil;
    return [response objectForKey:@"data"];
}

+(BOOL)writeDataToCache:(NSString*)name params:(NSDictionary*)params content:(NSString*)content
{
    NSString* filename = [ServerEngine getMD5FromRequest:name params:params];
    filename = [NSString stringWithFormat:@"%@%@",DE.cachePath,filename];
    return [StorageEngine writeFile:filename content:content];
}

+(BOOL)removeRequestCache:(NSString *)name params:(NSDictionary *)params
{
    NSString* filename = [ServerEngine getMD5FromRequest:name params:params];
    filename = [NSString stringWithFormat:@"%@%@",DE.cachePath,filename];
    return [StorageEngine removeFile:filename];
}

-(NSDictionary*)serverCall:(NSString *)name params:(NSDictionary *)params callback:(CallbackBlock)callback needCache:(BOOL)needCache
{
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:[self baseUrl]]];
    
    [httpClient postPath:self.serverUri parameters:@{@"string" : [self encodeCmd:name params:params]} success:^(AFHTTPRequestOperation *operation, id responseObject) {
        
        NSString *responseStr = operation.responseString;
        
        NSDictionary* response = [ServerEngine decodeCmd:responseStr];
        
        NSDictionary* head = [response objectForKey:@"head"];
        NSDictionary* data = [response objectForKey:@"data"];
        BOOL success = [(NSString*)[head objectForKey:@"success"] isEqualToString:@"true"] ? YES : NO;
        int code = [[head objectForKey:@"code"] intValue];
        NSString* desc = (NSString*)[head objectForKey:@"desc"];
        
        if ( [DE serverCallback:name params:params success:success response:response] && callback )
        {
            callback(success,code,desc,data,params);
        }
        
        if ( success && needCache )
            [ServerEngine writeDataToCache:name params:params content:responseStr];
        
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"[HTTPClient Error]: %@", error.localizedDescription);
        
        if (callback) {
            callback(NO,-1,@"连接失败",nil,params);
        }
    }];
    [httpClient release];
    httpClient =nil;
    return [ServerEngine readDataFromCache:name params:params];
}

-(NSDictionary*)serverCall:(NSString *)name params:(NSDictionary *)params callback:(CallbackBlock)callback
{
    return [self serverCall:name params:params callback:callback needCache:NO];
}

-(NSString*)baseUrl
{
    return [NSString stringWithFormat:@"http://%@:%@/",self.serverName,self.serverPort];
}

#pragma mark - DES 

const Byte iv[] = {1,2,3,4,5,6,7,8};
+(NSString *)encryptDES:(NSString *)plainText key:(NSString *)key
{
    NSString *ciphertext = nil;
    NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [textData length];
    int buffer_length = [textData length] * 2;
    unsigned char* buffer = (unsigned char*)malloc(sizeof(unsigned char)*buffer_length);
    memset(buffer, 0, sizeof(char));
    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding,
                                          [key UTF8String], kCCKeySizeDES,
                                          iv,
                                          [textData bytes], dataLength,
                                          buffer, buffer_length,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
         ciphertext = [data base64Encoding];
        
    }
    free(buffer);
    return ciphertext;
}

+(NSString *)decryptDES:(NSString *)cipherText key:(NSString *)key
{
    NSString *plaintext = nil;
    NSData *cipherdata = [ServerEngine dataWithBase64EncodedString:cipherText];// [NSData dataFromBase64String:cipherText];
    int buffer_length = [cipherdata length] * 2;
    unsigned char* buffer = (unsigned char*)malloc(sizeof(unsigned char)*buffer_length);
    memset(buffer, 0, sizeof(char));
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
                                          kCCOptionPKCS7Padding,
                                          [key UTF8String], kCCKeySizeDES,
                                          iv,
                                          [cipherdata bytes], [cipherdata length],
                                          buffer, buffer_length,
                                          &numBytesDecrypted);
    if(cryptStatus == kCCSuccess) {
        NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
//        plaintext = [[NSString alloc]initWithData:plaindata encoding:NSUTF8StringEncoding];
        NSString *temop =[[NSString alloc]initWithData:plaindata encoding:NSUTF8StringEncoding];
        plaintext = [NSString stringWithFormat:@"%@",temop];
        temop = nil;

    }
    free(buffer);
    return plaintext;
}

+ (NSData *)dataWithBase64EncodedString:(NSString *)string
{

    if ( string == nil || [string length] == 0 )
        return [NSData data];
    
    static char *decodingTable = NULL;
    if (decodingTable == NULL)
    {
        decodingTable = malloc(256);
        if (decodingTable == NULL)
            return nil;
        memset(decodingTable, CHAR_MAX, 256);
        NSUInteger i;
        for (i = 0; i < 64; i++)
            decodingTable[(short)base64EncodeLookup[i]] = i;
    }
    
    const char *characters = [string cStringUsingEncoding:NSASCIIStringEncoding];
    if (characters == NULL)     //  Not an ASCII string!
        return nil;
    char *bytes = malloc((([string length] + 3) / 4) * 3);
    if (bytes == NULL)
        return nil;
    NSUInteger length = 0;
    
    NSUInteger i = 0;
    while (YES)
    {
        char buffer[4];
        short bufferLength;
        for (bufferLength = 0; bufferLength < 4; i++)
        {
            if (characters[i] == '\0')
                break;
            if (isspace(characters[i]) || characters[i] == '=')
                continue;
            buffer[bufferLength] = decodingTable[(short)characters[i]];
            if (buffer[bufferLength++] == CHAR_MAX)      //  Illegal character!
            {
                free(bytes);
                return nil;
            }
        }
        
        if (bufferLength == 0)
            break;
        if (bufferLength == 1)      //  At least two characters are needed to produce one byte!
        {
            free(bytes);
            return nil;
        }
        
        //  Decode the characters in the buffer to bytes.
        bytes[length++] = (buffer[0] << 2) | (buffer[1] >> 4);
        if (bufferLength > 2)
            bytes[length++] = (buffer[1] << 4) | (buffer[2] >> 2);
        if (bufferLength > 3)
            bytes[length++] = (buffer[2] << 6) | buffer[3];
    }
    
    bytes = realloc(bytes, length);
    return [NSData dataWithBytesNoCopy:bytes length:length];
}



#pragma mark - Property

-(NSString*)serverName
{
    return _serverName;
}

-(NSString*)serverProjectName
{
    return _serverProjectName;
}

-(NSString*)serverPort
{
    return _serverPort;
}

-(NSString*)serverUri
{
    return [NSString stringWithFormat:@"%@/%@",self.serverProjectName,_serverUri];
}

-(void)setServerName:(NSString *)serverName
{
    _serverName = serverName;
    [_serverName retain];
}

-(void)setServerProjectName:(NSString *)serverProjectName
{
    _serverProjectName = serverProjectName;
    [_serverProjectName retain];
}

-(void)setServerPort:(NSString *)serverPort
{
    _serverPort = serverPort;
    [_serverPort retain];
}

-(void)setServerUri:(NSString *)serverUri
{
    _serverUri = serverUri;
    [_serverUri retain];
}

@end
